After reading Paul Graham's "Hackers and Painters", I wanted learn "Common Lisp". I found "lisp-koans" to be a great resource for me to get started. After completing about 25 lessons of 27 koans, I wanted to try and create a REST api project with lisp. I found creating a REST API to be a difficult taks because I didn't know much about project structure and how to move forward with a lisp project. Therefore I decided to document the process I folowed to help someone else to get started. This may not be the best approach but it should help you to get started and move along with a REST API development.
I'm using sbcl
as "Common Lisp" implementation and Quicklisp
for package management. Lisp Cookbook Getting Started
guide provides a good starting point for installing Lisp
and Quicklisp
package manager.
brew install sbcl
brew install rlwrap
curl -O https://beta.quicklisp.org/quicklisp.lisp
sbcl --load quicklisp.lisp
After "Common Lisp" REPL loads
(quicklisp-quickstart:install)
(ql:add-to-init-file)
In order to install quickproject,
(ql:quickload "quickproject")
I found that location that I create new project is important if I want to load it from the sbcl
REPL after I make changes. We are going to create a new project cl-start
in ~/quicklisp/local-projects
so that quicklisp
able to discover and load this project without any issues. In addition, we will be using Hunchentoot
(quickproject:make-project "~/quicklisp/local-projects/cl-start" :depends-on '(hunchentoot))
WARNING: Coercing "~/quicklisp/local-projects/cl-start" to directory
"cl-start"
$tree ~/quicklisp/local-projects/cl-start
├── README.md
├── cl-start.asd
├── cl-start.lisp
└── package.lisp
Since we added project at ~/quicklisp/local-projects
we can load our project with (ql:quickload "cl-start")
Add following code to cl-start.lisp
;;;; cl-start.lisp
(in-package #:cl-start)
;; Add a simple prefix dispatcher to the *dispatch-table*
(setq *dispatch-table*
`(,(create-prefix-dispatcher "/hello" 'hello-page)))
;; Handler functions either return generated Web pages as strings,
;; or write to the output stream returned by write-headers
(defun hello-page ()
"Hello !")
(defun main ()
(start (make-instance 'easy-acceptor :port 8080))
(sb-thread:join-thread (find-if
(lambda (th)
(string= (sb-thread:thread-name th) "hunchentoot-listener-*:8080"))
(sb-thread:list-all-threads))))
package.lisp
contains following
;;;; package.lisp
(ql:quickload '(:hunchentoot))
(defpackage #:cl-start
(:use #:cl #:hunchentoot)
(:export :main))
Create a makefile with following content.
all: build
build:
sbcl --load cl-start.asd \
--eval '(ql:quickload :cl-start)' \
--eval "(sb-ext:save-lisp-and-die #p\"cl-start\" :toplevel #'cl-start:main :executable t)"
make
sbcl --load cl-start.asd \
--eval '(ql:quickload :cl-start)' \
--eval "(sb-ext:save-lisp-and-die #p\"cl-start\" :toplevel #'cl-start:main :executable t)"
This is SBCL 1.5.8, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
To load "cl-start":
Load 1 ASDF system:
cl-start
; Loading "cl-start"
.....To load "hunchentoot":
Load 1 ASDF system:
hunchentoot
; Loading "hunchentoot"
[undoing binding stack and other enclosing state... done]
[performing final GC... done]
[defragmenting immobile space... (fin,inst,fdefn,code,sym)=1597+1189+21847+21078+25890... done]
[saving current Lisp image into cl-start:
writing 0 bytes from the read-only space at 0x20000000
writing 1264 bytes from the static space at 0x20100000
writing 36798464 bytes from the dynamic space at 0x1000000000
writing 2199552 bytes from the immobile space at 0x20300000
writing 14176256 bytes from the immobile space at 0x21b00000
done]
Above make
command will create a cl-start
executable that we use to run our HTTP Server
./cl-start
On another window use curl
to send http requests to the server.
http "http://localhost:8080/hello"
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 7
Content-Type: text/html; charset=utf-8
Date: Wed, 11 Dec 2019 02:07:41 GMT
Keep-Alive: timeout=20
Server: Hunchentoot 1.2.38
Hello !
Complete source code for this project is available in github.